#ifndef CALCULATOR_H_20240514
#define CALCULATOR_H_20240514

#include <cstddef>

/**
 * 子弹轨迹计算器
 */
class Calculator {
 public:
  //! 环境参数
  struct Env {
    double G = 9.81;    //! 重力加速度
    double T = 20;      //! 温度(摄氏度)
    double AP = 1;      //! 大气压(bar)
  };

  //! 子弹参数
  struct Bullet {
    double m = 0; //! 质量(kg)
    double d = 0; //! 直径(m)
    double Cd = 0.47;   //! 球体的阻力系数
  };

  //! 目标信息
  struct Target {
    double distance = 0;  //! 直线距离(m)
    double angle = 0;     //! 仰角('C)
  };

 public:
  void setBullet(const Bullet &b);
  void setTarget(const Target &t);
  void setSpeed(double v);
  void setTimes(size_t times) { times_ = times; }
  void setEnv(const Env &e);

  //! 计算击中目标所需要的俯仰角，飞行时长，水平与垂直速度
  struct AngleResult {
    double start_angle = 0;     //! 俯仰角('C)
    double relative_angle = 0;  //! 相对俯仰角('C)
    double relative_mil = 0;    //! 相对俯仰密位(mil)

    double tof = 0;         //! 飞行时长(sec)

    double v = 0;           //! 速度(m/s)
    double final_angle = 0; //! 角度('C)
    double v_h = 0;         //! 水平速度(m/s)
    double v_v = 0;         //! 垂直速度(m/s)

    double start_E = 0;     //! 初始动能(J)
    double start_EpA = 0;   //! 初始比动能(J/m2)

    double E = 0;       //! 动能(J)
    double EpA = 0;     //! 比动能(J/m2)

    double percent = 0; //! 动能存留百分比
    double error = 0;   //! 垂直误差(m)
    double max_h_distance = 0;  //! 最大水平飞行距离(m)
  };

  bool findBestFlyAngle(AngleResult &result);

  void fly(double angle, double ul);

 protected:
  void updateInnerData();

 private:
  Env env_;
  Bullet bullet_;
  Target target_;         //! 目标信息
  double start_v_ = 0;    //! 初速
  size_t times_ = 10000;  //! 计算轮次

  double A_ = 0;
  double start_E_ = 0;
  double Rx_ = 0;
  double h_L_ = 0;
  double v_L_ = 0;
};

#endif //CALCULATOR_H_20240514
